﻿Shader "PBR"
{
    Properties
    {
        _BaseColor("Color",Color) = (1,1,1,1)
        _BaseMap("Texture",2D) = "white"{}
        [NoScaleOffset]_BumpMap("NormalMap",2D) = "bump" {}
        [NoScaleOffset]_MetallicMap("Metallic", 2D) = "white" {}
        [NoScaleOffset]_OcclusionMap("Occlusion",2D) = "white" {}
        _Metallic("Metallic",Range(0,1)) = 0.5
        _Smoothness("Smoothness",Range(0,1)) = 0.5
        _BumpScale("NormalScale",Range(-1,1)) = 1
    }
    SubShader
    {
        Tags
        {
            "RenderPipeline"="UniversalRenderPipeline"
            "LightMode"="UniversalForward"
            "RenderType"="Opaque"
        }

        HLSLINCLUDE
        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

        #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
        #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
        #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
        #pragma multi_compile _ _SHADOWS_SOFT

        TEXTURE2D(_BaseMap);        SAMPLER(sampler_BaseMap);
        TEXTURE2D(_MetallicMap);    SAMPLER(sampler_MetallicMap);
        TEXTURE2D(_OcclusionMap);   SAMPLER(sampler_OcclusionMap);
        TEXTURE2D(_BumpMap); SAMPLER(sampler_BumpMap);

        CBUFFER_START(UnityPerMaterial)
        float4 _BaseMap_ST;
        half4 _BaseColor;
        half _Metallic;
        half _Smoothness;
        half _BumpScale;
        CBUFFER_END
        ENDHLSL
        
        pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            struct a2v
            {
                float4 positionOS : POSITION;
                float3 normalOS : NORMAL;
                float4 tangentOS : TANGENT;
                float2 texcoord : TEXCOORD;
            };
            struct v2f
            {
                float4 positionCS : SV_POSITION;
                float3 positionWS : TEXCOORD0;
                half3 normalWS : NORMAL;
                half3 tangent : TANGENT;
                half3 bitangent : TEXCOORD1;
                half2 texcoord : TEXCOORD2;
            };
            
            v2f vert(a2v v)
            {
                v2f o;
                VertexPositionInputs vertexInput = GetVertexPositionInputs(v.positionOS.xyz);
                o.positionCS = vertexInput.positionCS;
                o.positionWS = vertexInput.positionWS;
                VertexNormalInputs normalInput = GetVertexNormalInputs(v.normalOS, v.tangentOS);
                o.normalWS = normalInput.normalWS;
                o.tangent = normalInput.tangentWS;
                o.bitangent = normalInput.bitangentWS;
                o.texcoord = TRANSFORM_TEX(v.texcoord,_BaseMap);
                return o;
            }

            half4 frag(v2f i):SV_Target
            {
                Light light = GetMainLight(TransformWorldToShadowCoord(i.positionWS));
                float3 lightDir = normalize(light.direction);
                half3 normalTS = UnpackNormalScale(SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, i.texcoord),_BumpScale);
                half3 normalWS = normalize(TransformTangentToWorld(normalTS, half3x3(i.tangent, i.bitangent, i.normalWS)));
                half3 viewDir = normalize(GetCameraPositionWS() - i.positionWS);

                half4 albedo = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, i.texcoord);
                half4 metallicMap = SAMPLE_TEXTURE2D(_MetallicMap, sampler_MetallicMap, i.texcoord);    
                half4 occlusionMap = SAMPLE_TEXTURE2D(_OcclusionMap,sampler_OcclusionMap,i.texcoord);
                half metallic = metallicMap.r * _Metallic;
                half smoothness = metallicMap.a *_Smoothness; 
                half occlusion = occlusionMap.r;
                half specular = 1;
                half emission = 0;
                half alpha = 1;

                BRDFData data;
                InitializeBRDFData(albedo.rgb, metallic, specular, smoothness, alpha,data);
                half3 bakedGI = SampleSH(normalWS);
                MixRealtimeAndBakedGI(light,normalWS,bakedGI, 1);
                half3 color = GlobalIllumination(data, bakedGI, occlusion, normalWS, viewDir);
                color += LightingPhysicallyBased(data, light, normalWS, viewDir);
                #ifdef _ADDITIONAL_LIGHTS
                    uint pixelLightCount = GetAdditionalLightsCount();
                    for (uint lightIndex = 0u; lightIndex < pixelLightCount; ++lightIndex)
                    {
                        Light light = GetAdditionalLight(lightIndex,i.positionWS);
                        color += LightingPhysicallyBased(data, light, normalWS,viewDir);
                    }
                #endif
                color += emission;
                return half4(color, alpha);
            }
            ENDHLSL
        }

        pass
        {
            Name "ShadowPass"
            Tags{"LightMode"="ShadowCaster"}
            HLSLPROGRAM
            #pragma vertex vertshadow
            #pragma fragment fragshadow

            struct a2v
            {
                float4 positionOS : POSITION;
                float3 normalOS : NORMAL;
                float2 texcoord : TEXCOORD;
            };
            struct v2f
            {
                float4 positionCS : SV_POSITION;
                float3 positionWS : TEXCOORD0;
                float3 normalWS : TEXCOORD1;
                float2 texcoord : TEXCOORD2;
            };
            
            v2f vertshadow(a2v v)
            {
                v2f o;
                Light MainLight = GetMainLight();
                o.texcoord = TRANSFORM_TEX(v.texcoord,_BaseMap);
                o.positionWS = TransformObjectToWorld(v.positionOS.xyz);
                o.normalWS = TransformObjectToWorldNormal(v.normalOS.xyz);
                o.positionCS = TransformWorldToHClip(ApplyShadowBias(o.positionWS,o.normalWS,MainLight.direction));
                #if UNITY_REVERSED_Z
                    o.positionCS.z = min(o.positionCS.z,o.positionCS.w * UNITY_NEAR_CLIP_VALUE);
                #else
                    o.positionCS.z = max(o.positionCS.z,o.positionCS.w * UNITY_NEAR_CLIP_VALUE);
                #endif
                return o;
            }

            half4 fragshadow(v2f i):SV_Target
            {
                #ifdef CUT_ON
                    float alpha = SAMPLE_TEXTURE2D(_BaseMap,sampler_BaseMap,i.texcoord).a;
                    clip(alpha -_Cutoff);
                #endif
                return 0;
            }
            ENDHLSL
        }
    }   
}